// dotnet $DOTNET_CSC_DLL -nologo -t:library -r:"../../Backend/System.dll" -r:"../../Backend/System.Collections.dll" -r:"../../The Scroll of Taiwu_Data/Managed/0Harmony.dll" -r:"../../Backend/netstandard.dll" -r:"../../Backend/mscorlib.dll" -r:"../../Backend/GameData.dll" -r:"../../Backend/Redzen.dll" -r:"../../The Scroll of Taiwu_Data/Managed/TaiwuModdingLib.dll" -r:"../../Backend/System.Console.dll" -r:"../../Backend/System.Private.CoreLib.dll" -r:"../../Backend/System.Runtime.dll" -unsafe -optimize -deterministic -debug Backend.cs *.CS -out:Backend.dll
// -r:"../../Backend/System.IO.FileSystem.dll"

//! 编译方法，目前来说只能是自己改上面那行字，把缺的东西都补齐，之后送命令提示符或者用python脚本编译。
//! windows就是一坨shit……连通配符都不支持……不然我至少能写出类似 dotnet C:\Program Files\dotnet\sdk\*\Roslyn\bincore\csc.dll 这样的语法

// -r:"../../The Scroll of Taiwu_Data/Managed/Mono.Cecil.dll" -r:"../../The Scroll of Taiwu_Data/Managed/System.Core.dll"   -r:"../../The Scroll of Taiwu_Data/Managed/System.Composition.AttributedModel.dll" -r:"../../Backend/System.Runtime.dll"
/**
 *  Everyone's Unity Game Plugin
 *  Copyright (C) 2022 Neutron3529
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
//! 这是一个自带文档注释的Mod，虽然代码很shit，但里面有不少注释，或许会对之后准备玩过月逻辑的人有帮助。
//! 所有文档注释会用//!开头，请注意搜索
//! 首先是前后端，前端对后端的调用会先被塞进 ProcessMethodCall，之后分发给对应domain的CallMethod，由CallMethod进行进一步的分发。借助这一点，我们可以快速找到前端调用究竟是在使用哪个函数。
using System;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using HarmonyLib;
using Utils;

namespace NeutronFightsConchship;
[TaiwuModdingLib.Core.Plugin.PluginConfig("NeutronFightsConchship","Neutron3529","0.1.0")]
public partial class NeutronFightsConchship : TaiwuModdingLib.Core.Plugin.TaiwuRemakePlugin {
    public override void Initialize()=>this.HarmonyInstance = new RobustHarmonyInstance(this.GetGuid());
    public override void Dispose()=>this.HarmonyInstance.UnpatchSelf();
    public static void logger(string s)=>GameData.Utilities.AdaptableLog.Info(s);
    public static void logwarn(string s)=>GameData.Utilities.AdaptableLog.Warning("<color=#FFFF00>"+s+"</color>",true);
    public RobustHarmonyInstance HarmonyInstance;
    private bool enable(string key){
        try {
            return _enable(key);
        } catch(Exception ex){
            logwarn("enable 出错，出错键值为\""+key+"\"，错误原因是"+ex.Message);
            return false;
        }
    }
    private bool _enable(string key){
        bool enabled=false;
        GameData.Domains.DomainManager.Mod.GetSetting(this.ModIdStr, key, ref enabled);
        return enabled;
    }
    public override void OnModSettingUpdate(){
        this.HarmonyInstance.UnpatchSelf();
        if(enable("LP"))this.HarmonyInstance.PatchAll(typeof(ModDomainLoadAllEventPackages));
        if(enable("RY"))this.HarmonyInstance.PatchAll(typeof(TaiwuEventDomainGetEventDisplayData));
        if(enable("SS"))this.HarmonyInstance.PatchAll(typeof(StripSave));
    }
    [HarmonyPatch(typeof(GameData.Domains.World.WorldDomain),"PostAdvanceMonth")]
    public static class StripSave {
        static FieldInfo _objects=typeof(GameData.Domains.Character.CharacterDomain).GetField("_objects",(BindingFlags)(-1)); // Dictionary<int, GameData.Domains.Character.Character>
        static FieldInfo _relatedCharIds=typeof(GameData.Domains.Character.CharacterDomain).GetField("_relatedCharIds",(BindingFlags)(-1)); // Dictionary<int, GameData.Domains.Character.Relation.RelatedCharacters>
        public static void Postfix(GameData.Common.DataContext context){
            var sw=System.Diagnostics.Stopwatch.StartNew();
            var alive=new HashSet<int>(((Dictionary<int, GameData.Domains.Character.Character>)(_objects.GetValue(GameData.Domains.DomainManager.Character))).Keys);
            var relatedCharIds=(Dictionary<int, GameData.Domains.Character.Relation.RelatedCharacters>)(_relatedCharIds.GetValue(GameData.Domains.DomainManager.Character));
            var deadKeys=(new HashSet<int>(relatedCharIds.Keys));
            deadKeys.ExceptWith(alive);
            sw.Stop();
            logger($"alive.Count={alive.Count} deadKeys.Count={deadKeys.Count} sw={sw.Elapsed.TotalMilliseconds}");
            sw.Restart();
            var hs=new HashSet<int>();
            var counter=0;
            foreach(var x in deadKeys){
                hs.Clear();
                relatedCharIds[x].GetAllRelatedCharIds(hs, true);
                hs.IntersectWith(deadKeys);
                foreach(var y in hs){
                    counter++;
                    GameData.Domains.DomainManager.Character.RemoveRelation(context, x, y);
                }
            }
            sw.Stop();
            logger($"counter={counter} sw={sw.Elapsed.TotalMilliseconds}");
        }
    }
    [HarmonyPatch(typeof(GameData.Domains.Mod.ModDomain),"LoadAllEventPackages")]
    public static class ModDomainLoadAllEventPackages {
        public static bool Prefix(List<GameData.Domains.Mod.ModId>___LoadedMods, Dictionary<string, GameData.Domains.Mod.ModInfo> ___ModInfoDict){
            foreach (var modId in ___LoadedMods) {
                var modInfo = ___ModInfoDict[modId.ToString()];
                string eventsDir = Path.Combine(modInfo.DirectoryName, "Events");
                foreach (string eventPackageName in modInfo.EventPackages) {
                    logger(" - Loading events from " + eventPackageName);
                    string packageDir = Path.Combine(eventsDir, "EventLib", eventPackageName);
                    string pdbDir = Path.Combine(eventsDir, "EventLib", eventPackageName.Replace(".dll",".pdb"));
                    string langDir = Path.Combine(eventsDir, "EventLanguages");
                    byte[] buffer = File.ReadAllBytes(packageDir);
                    byte[] buffer2 = File.Exists(pdbDir)?File.ReadAllBytes(pdbDir):null;
                    Assembly assembly = Assembly.Load(buffer, buffer2);
                    GameData.Domains.DomainManager.TaiwuEvent.LoadEventPackageFromAssembly(assembly, packageDir, langDir, modId.ToString());
                }
            }
            return false;
        }
    }
    [HarmonyPatch(typeof(GameData.Domains.TaiwuEvent.TaiwuEventDomain),"GetEventDisplayData")]
    public static class TaiwuEventDomainGetEventDisplayData {
        public static IEnumerable<CodeInstruction> Transpiler(MethodBase __originalMethod, IEnumerable<CodeInstruction> instructions) {
            return instructions.MethodReplacer(typeof(System.Console).GetMethod("WriteLine",new Type[]{typeof(string)}), typeof(NeutronFightsConchship).GetMethod("logwarn"));
        }
    }
}

